package cn.zhuo.knowledge.util.transmittable;

import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.ttl.TtlRunnable;
import com.alibaba.ttl.threadpool.TtlExecutors;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

/**
 * <p>
 *
 * @author z2huo
 */
@Slf4j
class Main {

    public void executorServiceInheritableThreadLocalTest() {

        IntegerHolder.set(40);
        log.info("parent thread {}, value is {}", Thread.currentThread().getName(), IntegerHolder.get());

        try (ExecutorService executorService = Executors.newFixedThreadPool(10)) {
            Runnable runnable = () -> {
                IntegerHolder.increment();
                log.info("thread {}, after increment value is {}", Thread.currentThread().getName(), IntegerHolder.get());
            };
            executorService.execute(runnable);
            // 重复执行同一个 Runnable
            executorService.execute(runnable);
        } finally {
            IntegerHolder.remove();
        }
    }

    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
            10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)
    );

    public Main() {
        this.init();
    }

    public void init() {
        // InheritableThreadLocal 只有在线程创建时，子线程会获取父线程中所有可继承线程局部变量的初始值
        // 因为所有的核心线程都预先创建了，所以子线程获取不到父线程中设置的值
        EXECUTOR.prestartAllCoreThreads();
    }

    public void destroy() {
        EXECUTOR.shutdown();
    }

    public void threadPoolInheritableThreadLocalTest() {

        IntegerHolder.set(50);
        log.info("parent thread {}, value is {}", Thread.currentThread().getName(), IntegerHolder.get());

        Runnable runnable = () -> {
            IntegerHolder.increment();
            log.info("thread {}, after increment value is {}", Thread.currentThread().getName(), IntegerHolder.get());
        };

        EXECUTOR.execute(runnable);
        // 重复执行同一个 Runnable
        EXECUTOR.execute(runnable);

        IntegerHolder.remove();
    }

    /**
     * 修饰 Runnable
     */
    public void ttlThreadPoolTest() {

        IntegerHolder.set(60);
        log.info("parent thread {}, value is {}", Thread.currentThread().getName(), IntegerHolder.get());

        TtlRunnable ttlRunnable = TtlRunnable.get(() -> {
            IntegerHolder.increment();
            log.info("thread {}, after increment value is {}", Thread.currentThread().getName(), IntegerHolder.get());
        });
        EXECUTOR.execute(ttlRunnable);

        // 重复执行同一个 TtlRunnable
        // 如果同一个任务下一次提交时不执行修饰而仍然使用上一次的TtlRunnable，则提交的任务运行时会是之前修饰操作所抓取的上下文。
        EXECUTOR.execute(ttlRunnable);

        IntegerHolder.remove();
    }

    /**
     * 修饰线程池
     */
    public void ttlExecutorsTest() {
        ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(EXECUTOR);

        IntegerHolder.set(70);
        log.info("parent thread {}, value is {}", Thread.currentThread().getName(), IntegerHolder.get());

        Runnable runnable = () -> {
            IntegerHolder.increment();
            log.info("thread {}, after increment value is {}", Thread.currentThread().getName(), IntegerHolder.get());
        };

        ttlExecutorService.execute(runnable);
        // 重复执行同一个 TtlRunnable
        ttlExecutorService.execute(runnable);

        IntegerHolder.remove();
    }

    /**
     * 使用 Java Agent 来修饰JDK线程池实现类
     */
    public void ttlJavaAgentTest() {

    }

    public static void main(String[] args) {

        Main main = new Main();

        main.executorServiceInheritableThreadLocalTest();
        ThreadUtil.sleep(1, TimeUnit.SECONDS);
        System.out.println();

        main.threadPoolInheritableThreadLocalTest();
        ThreadUtil.sleep(1, TimeUnit.SECONDS);
        System.out.println();

        main.ttlThreadPoolTest();
        ThreadUtil.sleep(1, TimeUnit.SECONDS);
        System.out.println();

        main.ttlExecutorsTest();
        ThreadUtil.sleep(1, TimeUnit.SECONDS);
        System.out.println();

        main.destroy();
    }

}
